const path = require('path');
const glob = require('glob');
const _ = require('lodash');
const webpack = require('webpack');
const CleanPlugin = require('clean-webpack-plugin');
const ProgressPlugin = webpack.ProgressPlugin;
const IgnorePlugin = webpack.IgnorePlugin;
const BannerPlugin = webpack.BannerPlugin;
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const appTitle = 'Bookstore';
// 源文件目录。
const srcDir = path.resolve(__dirname, '../src');
// 构建目录。
const buildDir = path.resolve(__dirname, '../build');
// 公共文件目录名。
const publicDirName = 'public';
// 公共文件目录。
const publicDir = path.resolve(__dirname, '..', publicDirName);
// 构建后的公共文件目录。
const buildPublicDir = path.resolve(buildDir, publicDirName);

const relativePath = (from, to) => {
    const result = path.relative(from, to).replace(/\\/g, '\/');
    return result ? result : '.';
}

const findEntries = (pattern, ek) => {
    return glob.sync(pattern, {
        cwd: srcDir,
        root: srcDir,
        mark: true,
        matchBase: true,
        nocase: true,
        follow: false,
        absolute: true,
    }).map(p => {
        let rp = relativePath(srcDir, p);
        let key = ek(rp)

        if (key !== null) {
            console.debug('Add entry: "%s" -> "%s"', key, rp);

            return {
                key: key,
                value: './' + rp,
            };
        } else {
            return {
                key: null,
                value: null,
            };
        }
    }).filter(item => item.key);
};

console.debug('Finding entries at "%s" ...\n-----------', srcDir);

const entries = findEntries('*.tsx', rp => !/components\//.test(rp) ? rp.substring(0, rp.length - 4) : null);

console.debug('-----------\n%d entries added in total\n', entries.length);

const htmlWebpackPlugins = _.map(entries, entry => {
    // 不需要为测试类生成页面。
    if (/\btest\b/.test(entry.key)) {
        return null;
    }

    let current = path.dirname(entry.key);
    let name = path.basename(entry.key);
    if (current === '.' || current === '') {
        current = '/';
    } else {
        current = '/' + current;
    }

    const relativePublic = src => {
        return relativePath(current, path.join('/' + publicDirName, src));
    };

    return new HtmlWebpackPlugin({
        inject: false,
        template: 'assets/template.ejs',
        filename: entry.key + '.html',
        title: appTitle,
        meta: [
            { 'charset': 'utf-8' },
            { 'viewport': 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' },
            { 'theme-color': '#000000' },
        ],
        mobile: true,
        chunks: ['runtime', 'vendors', entry.key],
        minify: {
            collapseWhitespace: true,
            collapseBooleanAttributes: true,
            collapseInlineTagWhitespace: true,
            preserveLineBreaks: true,
            ignoreCustomComments: true,
            removeComments: true,
            removeEmptyAttributes: true,
            removeRedundantAttributes: true,
            removeScriptTypeAttributes: true,
            removeStyleLinkTypeAttributes: true,
            useShortDoctype: true,
            html5: true,
        },
        appMountIds: ['root'],
        links: [
            relativePublic('css/semantic.united.min.css'),

            { rel: 'icon', href: relativePublic('favicon16.ico'), sizes: '16x16' },
            { rel: 'icon', href: relativePublic('favicon32.ico'), sizes: '32x32' },
            { rel: 'icon', href: relativePublic('favicon48.ico'), sizes: '48x48' },
            { rel: 'manifest', href: relativePublic('manifest.json') }
        ],
        unsupportedBrowser: true,
        window: {
            env: {
                current,
                name,
                base: relativePath(current, '/'),
                api: relativePath(current, '/api'),
            }
        },
        scripts: [
            'https://unpkg.com/babel-polyfill@6.26.0/dist/polyfill.min.js',
            'https://unpkg.com/url-search-params-polyfill@6.0.0/index.js',
            'https://unpkg.com/react@16.8.6/umd/react.production.min.js',
            'https://unpkg.com/react-dom@16.8.6/umd/react-dom.production.min.js',
            'https://unpkg.com/lodash@4.17.11/lodash.js',
            'https://unpkg.com/moment@2.24.0/moment.js',
            'https://unpkg.com/moment@2.24.0/locale/zh-cn.js',
        ],
        mobile: true,
        xhtml: true,
    });
}).filter(plugin => plugin);

// const polyfillChunks = ['babel-polyfill', 'react-app-polyfill/ie9', 'url-search-params-polyfill',];

module.exports = {
    mode: 'development',

    context: srcDir,

    entry: _.zipObject(_.map(entries, entry => entry.key), _.map(entries, entry => entry.value)),

    output: {
        path: buildDir,
        filename: '[name].js',
        hashDigestLength: 8
    },

    resolve: {
        // Add `.ts` and `.tsx` as a resolvable extension.
        extensions: ['.ts', '.tsx', '.js'],
    },

    module: {
        rules: [
            {
                test: /\.tsx?$/,
                exclude: /\.test\./,
                use: 'ts-loader',
            },

            {
                test: /\.css$/,
                use: [
                    { loader: 'style-loader' },
                    { loader: 'css-loader' }
                ]
            },

            {
                test: /\.(png|jpg|gif|ico)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 4092,
                            name: '[path][name]-[hash:8].[ext]',
                            useRelativePath: true,
                        }
                    }
                ]
            },
        ]
    },

    plugins: [
        // 显示构建进度。
        new ProgressPlugin(),
        // 清理构建目录。
        new CleanPlugin(),
        // 在入口文件中加入包含生成时间戳的注释。
        new BannerPlugin({
            banner: 'Created at: ' + new Date().toISOString(),
            entryOnly: true,
        }),
        // 忽略moment库的本地化文件。
        new IgnorePlugin(/^\.\/locale$/, /moment$/),
        // 将公共文件复制到构建目录。
        new CopyWebpackPlugin([
            { from: publicDir, to: buildPublicDir },
        ]),
        // 为每个入口文件生成页面。
        ...htmlWebpackPlugins,
    ],

    externals: {
        'react': 'React',
        'react-dom': 'ReactDOM',
        'lodash': '_',
        'moment': 'moment',
    },

    optimization: {
        splitChunks: {
            cacheGroups: {
                vendors: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendors',
                    chunks: 'all',
                }
            }
        },
        runtimeChunk: 'single',
    },
};
